package com.zzyl.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.zzyl.constant.CacheConstants;
import com.zzyl.constant.SuperConstant;
import com.zzyl.dto.ResourceDto;
import com.zzyl.entity.Resource;
import com.zzyl.enums.BasicEnum;
import com.zzyl.exception.BaseException;
import com.zzyl.mapper.ResourceMapper;
import com.zzyl.service.ResourceService;
import com.zzyl.utils.EmptyUtil;
import com.zzyl.utils.NoProcessing;
import com.zzyl.vo.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Slf4j
@Service
public class ResourceServiceImpl implements ResourceService {

    @Autowired
    private ResourceMapper resourceMapper;


    @Override
    @Cacheable(value = "resourceList",key = "#resourceDto.hashCode()")
    public List<ResourceVo> findList(ResourceDto resourceDto) {
        log.error("findList数据从MySQL中获取");
        return resourceMapper.findList(resourceDto);
    }

    @Override
    @Cacheable(value = "resourceTree",key = "#resourceDto.hashCode()")
    public TreeVo tree(ResourceDto resourceDto) {
        log.error("tree数据从MySQL中获取");
        // 一次性把数据先查询出来
        List<ResourceVo> resourceVoList = resourceMapper.findList(resourceDto);
        TreeVo treeVo = TreeVo.builder().items(new ArrayList<>()).build();

        // 构建根
        TreeItemVo rootItemVo = TreeItemVo.builder().id(SuperConstant.ROOT_PARENT_ID).label("智慧养老院").children(new ArrayList<>()).build();
        treeVo.getItems().add(rootItemVo);

        // // 构建一级
        // for (ResourceVo vo1 : resourceVoList) {
        //     if (rootItemVo.getId().equals(vo1.getParentResourceNo())){
        //         TreeItemVo itemVo1 = TreeItemVo.builder().id(vo1.getResourceNo()).label(vo1.getResourceName()).children(new ArrayList<>()).build();
        //         rootItemVo.getChildren().add(itemVo1);
        //// 构建二级
        //         for (ResourceVo vo2 : resourceVoList) {
        //             if(itemVo1.getId().equals(vo2.getParentResourceNo())){
        //                 TreeItemVo itemVo2 = TreeItemVo.builder().id(vo2.getResourceNo()).label(vo2.getResourceName()).children(new ArrayList<>()).build();
        //                 itemVo1.getChildren().add(itemVo2);
        //
        //// 构建三级
        //                 for (ResourceVo vo3 : resourceVoList) {
        //                     if(itemVo2.getId().equals(vo3.getParentResourceNo())){
        //                         TreeItemVo itemVo3 = TreeItemVo.builder().id(vo3.getResourceNo()).label(vo3.getResourceName()).children(new ArrayList<>()).build();
        //                         itemVo2.getChildren().add(itemVo3);
        //                     }
        //                 }
        //             }
        //         }
        //     }
        //
        // }

        // 递归

        recursionTreeItem(rootItemVo,resourceVoList);


        return treeVo;
    }

    // 递归构建树形
    private void recursionTreeItem(TreeItemVo rootItemVo, List<ResourceVo> resourceVoList) {

        for (ResourceVo vo : resourceVoList) {
            if(rootItemVo.getId().equals(vo.getParentResourceNo())  && vo.getResourceType().equals(SuperConstant.MENU)){
                TreeItemVo itemVo = TreeItemVo.builder().id(vo.getResourceNo()).label(vo.getResourceName()).children(new ArrayList<>()).build();
                rootItemVo.getChildren().add(itemVo);
                recursionTreeItem(itemVo,resourceVoList);
            }
        }

    }

    @Override
    // @CacheEvict(value ="resourceTree",allEntries = true )
    @Caching(evict = {@CacheEvict(value ="resourceTree",allEntries = true ),
                @CacheEvict(value ="resourceList",allEntries = true )})
    public void add(ResourceDto resourceDto) {
        // 把DTO转成实体类

        Resource resource = BeanUtil.toBean(resourceDto, Resource.class);
        // 查询父资源
        Resource parentResource = resourceMapper.selectByResourceNo(resourceDto.getParentResourceNo());
        resource.setDataState(parentResource.getDataState());
        boolean isMenu = true;

        if(resourceDto.getResourceType().equals(SuperConstant.BUTTON)){
            isMenu  = false; ///如果是按钮就忽略层级
        }

        // 创建编号
        String resourceNo = createResourceNo(resource.getParentResourceNo(), isMenu);//如果是按钮就不用在乎层级
        resource.setResourceNo(resourceNo);
        resourceMapper.insert(resource);

    }





    /**
     * 创建资源的编号
     * @param parentResourceNo
     * @return
     */
    private String createResourceNo(String parentResourceNo,boolean isMenu) {

        //判断资源编号是否大于三级
        //100 001 000 000 000
        //100 001 001 000 000
        //100 001 001 001 000
        //100 001 001 001 001 001
        if (isMenu && NoProcessing.processString(parentResourceNo).length() / 3 >= 5) {
            throw new BaseException(BasicEnum.RESOURCE_DEPTH_UPPER_LIMIT);
        }

        //根据父资源编号查询子资源
        ResourceDto dto = ResourceDto.builder().parentResourceNo(parentResourceNo).build();
        List<ResourceVo> resources = resourceMapper.findList(dto);
        if (EmptyUtil.isNullOrEmpty(resources)) {
            //无下属节点，创建新的节点编号  100 001 001 001 000--->100 001 001 001 001
            return NoProcessing.createNo(parentResourceNo, false);
        } else {
            //有下属节点，在已有的节点上追加
            //先获取已有节点的最大值--100001003000000
            Long maxNo = resources.stream().map(resource -> {
                return Long.valueOf(resource.getResourceNo());
            }).max(Comparator.comparing(i -> i)).get();
            // 100,001,004,000,000
            return NoProcessing.createNo(String.valueOf(maxNo), true);
        }
    }

    @Override // 获取当前登录人的菜单
    public List<MenuVo> menus(Long userId) {
        List<MenuVo> menuVoList = resourceMapper.selectMenusByUserId(userId);
        // 根据menuVoList中的ParentResourceNo分组
        Map<String, List<MenuVo>> menuVoMap = menuVoList.stream().collect(Collectors.groupingBy(MenuVo::getParentResourceNo));


        // 获取每个菜单的子菜单
        for (MenuVo menuVo : menuVoList) {
            // menuVo.getResourceNo()
            // select * from sys_resurce where parent_resource_no = menuVo.getResourceNo()
            menuVo.setChildren(menuVoMap.get(menuVo.getResourceNo()));
            menuVo.setMeta(MenuMetaVo.builder().title(menuVo.getName()).build());
        }

        return  menuVoMap.get(SuperConstant.ROOT_PARENT_ID);

    }

    @Override
    @Caching(evict = {@CacheEvict(value ="resourceTree",allEntries = true ),
            @CacheEvict(value ="resourceList",allEntries = true )})
    public void update(ResourceDto resourceDto) {
        resourceMapper.updateByPrimaryKeySelective(BeanUtil.toBean(resourceDto, Resource.class));

    }


    /**
     * 启用或禁用资源
     * 该方法使用了注解@Transactional来确保方法内所有数据库操作要么全部成功，要么在发生异常时全部回滚
     * 主要目的是更新资源的状态（启用或禁用），并确保相关联的资源状态也得到相应的更新
     *
     * @param resourceDto 包含资源信息的数据传输对象
     */
    @Override
    @Caching(evict = {@CacheEvict(value = CacheConstants.RESOURCE_LIST ,allEntries = true),
            @CacheEvict(value = CacheConstants.RESOURCE_TREE ,allEntries = true)})
    @Transactional(rollbackFor = Exception.class)
    public void enableDisable(ResourceDto resourceDto) {
        // 将DTO对象转换为Resource实体对象
        Resource resource = BeanUtil.toBean(resourceDto, Resource.class);
        // 获取资源编号
        String resourceNo = resource.getResourceNo();
        // 获取资源状态
        String dataState = resource.getDataState();
        //获取父资源的状态
        Resource enable = resourceMapper.selectenableDisable(resource.getParentResourceNo());
        //父资源只有为启用才能继续
        if (enable.getDataState().equals(SuperConstant.DEFAULT_0)) {
            // 更新资源本身的状态
            resourceMapper.resourceNoenableDisable(resourceNo, dataState);
            // 更新与该资源关联的，以它为父资源的状态
            resourceMapper.parentResourceNoenableDisable(resourceNo, dataState);
            // 查询与当前资源相关的所有子资源
            List<Resource> strings = resourceMapper.selectResourceNo(resourceNo);
            // 遍历子资源，更新它们的状态
            for (Resource string : strings) {
                String resourceName = string.getResourceNo();
                // 更新以子资源为父的状态
                resourceMapper.parentResourceNoenableDisable(resourceName, dataState);
            }
        } else {
            throw new BaseException(BasicEnum.ELDER_ALREADY_resource);
        }
    }


    @Override
    @Caching(evict = {@CacheEvict(value = CacheConstants.RESOURCE_LIST ,allEntries = true),
            @CacheEvict(value = CacheConstants.RESOURCE_TREE ,allEntries = true)})
    @Transactional(rollbackFor = Exception.class)
    /**
     * 删除指定ID的资源，包括级联删除关联的子资源
     *
     * @param id 要删除的资源的ID
     */
    public void delete(String id) {
        // 查询与给定ID有直接关联的资源，子资源
        List<Resource> strings1 = resourceMapper.selectResourceNo(id);
        // 如果存在直接关联的资源
        if (!EmptyUtil.isNullOrEmpty(strings1)) {
            // 遍历每个子资源
            for (Resource string : strings1) {
                // 查询当前资源直接关联的子资源
                List<Resource> strings2 = resourceMapper.selectResourceNo(string.getResourceNo());
                // 如果存在子资源，则删除这些子资源的直接关联关系
                if (!EmptyUtil.isNullOrEmpty(strings2)) {
                    resourceMapper.deleteparentResourceNo(string.getResourceNo());
                }
            }
            // 删除给定ID的资源的直接关联关系
            resourceMapper.deleteparentResourceNo(id);
        }
        // 最后删除指定ID的资源
        resourceMapper.deleteResourceNo(id);

    }


}
